/*
 *    Copyright 2022 The DSMS Authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.dsms.modules.storagepool.task;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dsms.common.constant.*;
import com.dsms.common.exception.DsmsEngineException;
import com.dsms.common.remotecall.model.RemoteResponse;
import com.dsms.common.taskmanager.TaskStrategy;
import com.dsms.common.taskmanager.model.Step;
import com.dsms.common.taskmanager.model.Task;
import com.dsms.common.taskmanager.service.IStepService;
import com.dsms.common.taskmanager.service.ITaskService;
import com.dsms.dfsbroker.osd.osd.api.OsdApi;
import com.dsms.dfsbroker.osd.osd.model.remote.OSDResult;
import com.dsms.dfsbroker.osd.osd.request.UpdateOsdBucketRequest;
import com.dsms.dfsbroker.storagepool.model.dto.StoragePoolDiskManageDTO;
import com.dsms.modules.util.RemoteCallUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.List;


@Slf4j
@Service(TaskTypeEnum.TypeConstants.POOL_ADD_DISK)
public class StoragePoolAddDiskTask implements TaskStrategy {

    private final OsdApi osdApi;
    private final ITaskService taskService;
    private final IStepService stepService;
    private final GetCrushmapStepResult getCrushmapStepResult;

    @Autowired
    public StoragePoolAddDiskTask(OsdApi osdApi, ITaskService taskService, IStepService stepService, GetCrushmapStepResult getCrushmapStepResult) {
        this.osdApi = osdApi;
        this.taskService = taskService;
        this.stepService = stepService;
        this.getCrushmapStepResult = getCrushmapStepResult;
    }

    @Override
    public Task execute(Task task) {
        String taskParam = task.getTaskParam();
        if (ObjectUtils.isEmpty(taskParam)) {
            task.setTaskEndTime(LocalDateTime.now());
            task.setTaskErrorMessage("task parameter is null");
            task.setTaskStatus(TaskStatusEnum.FAIL.getStatus());
            return task;
        }
        StoragePoolDiskManageDTO storagePoolDiskManageDTO = JSONUtil.toBean(taskParam, StoragePoolDiskManageDTO.class);
        String poolName = storagePoolDiskManageDTO.getPoolName();
        String nodeName = storagePoolDiskManageDTO.getOsd().getNodeName();
        //get step task
        Integer taskId = task.getId();
        List<Step> steps = stepService.list(new LambdaQueryWrapper<Step>().eq(Step::getTaskId, taskId));
        for (Step step : steps) {
            try {
                int osdId = Integer.parseInt(step.getStepParam());
                OSDResult osd = osdApi.getOsdById(RemoteCallUtil.generateRemoteRequest(), osdId);
                //check if osd is existed
                if (ObjectUtils.isEmpty(osd.getOsd())) {
                    throw new DsmsEngineException(ResultCode.POOL_DISKNOTEXIST_ERROR);
                }
                //check if osd has been used
                if (!osd.getCrushLocation().getRoot().equals(CrushmapConst.DEFAULT_ROOT_BUCKET)) {
                    throw new DsmsEngineException(ResultCode.POOL_DISKUSEDD_ERROR);
                }

                //construct the host bucket name. example: pool1_node1
                String bucketName = poolName + CrushmapConst.BUCKET_NAME_CONNECTOR + nodeName;
                //move osd in crushmap
                RemoteResponse response = osdApi.updateOsdBucketRequest(RemoteCallUtil.generateRemoteRequest(), osdId, CrushFailureDomainEnum.HOST, bucketName);
                getCrushmapStepResult.getStepResponse(step, response, String.format(UpdateOsdBucketRequest.UPDATE_SUCCESS, osdId, osdId, bucketName), ResultCode.POOL_ADDDISK_ERROR.getMessage());
            } catch (Throwable e) {
                task.setTaskEndTime(LocalDateTime.now());
                task.setTaskStatus(TaskStatusEnum.FAIL.getStatus());
                task.setTaskErrorMessage(e.getMessage());
                return task;
            }
        }
        task.setTaskEndTime(LocalDateTime.now());
        task.setTaskStatus(TaskStatusEnum.FINISH.getStatus());
        return task;
    }

    @Override
    public boolean validateTask(String[] validateParam) {
        return taskService.validateTaskMessageAndTaskType(validateParam[0]);
    }

}

